
#pragma once

#include <assert.h>
#include <vector>
#include <algorithm>
using namespace std;


// Some function call interface
template <typename ...Types> class Callable;
template <typename R, typename ...Types>
class Callable<R (Types...)>
{
public:
	virtual ~Callable() {}

	R operator () (Types... args)
	{
		return call(args...);
	}

private:
	virtual R call(Types... args) = 0;
};


// Plain function, static methods and lambdas without closures
template <typename ...Types> class Functor;
template <typename R, typename ...Types>
class Functor<R (Types...)> : public Callable<R (Types...)>
{
public:
	typedef R (*Func)(Types...);

	Functor(Func f) : _func(f) {}
	~Functor() {}

private:
	Func _func;

	Functor() {}

	R call(Types... args)
	{
		assert(_func != nullptr);

		return _func(args...);
	}
};


// Non-static methods
template <typename C, typename R, typename ...Types>
class Functor<C, R (Types...)> : public Callable<R (Types...)>
{
public:
	typedef R (C::*Method)(Types...);

	Functor(C* o, Method m) : _object(o), _method(m) {}
	~Functor() {}

private:
	C* _object;
	Method _method;

	Functor() {}

	R call(Types... args)
	{
		assert(_object != nullptr && _method != nullptr);

		return (_object->*_method)(args...);
	}
};


// Lambdas with closures (and without actually) and functors
template <typename ...Types> class Closure;
template <typename L, typename R, typename ...Types>
class Closure<L, R (Types...)> : public Callable<R (Types...)>
{
public:
	Closure(L l) : _lambda(l) {}
	~Closure() {}

private:
	L _lambda;

	Closure() {}

	R call(Types... args)
	{
		return _lambda(args...);
	}
};


// Only void functional objects; for event handling
template <typename ...Types>
class Delegate
{
public:
	Delegate() {}
	~Delegate() 
	{
		for (auto el : _callables)
			delete el;
	}

	void addListener(Callable<void (Types...)>* callable)
	{
		assert(callable != nullptr);

		_callables.push_back(callable);
	}

	typedef void (*Func)(Types...);
	void addListener(Func func)
	{
		auto callable = new Functor<void (Types...)>(func);
		_callables.push_back(callable);
	}

	template <typename C, typename M>
	void addListener(C* c, M m)
	{
		auto callable = new Functor<C, void (Types...)>(c, m);
		_callables.push_back(callable);
	}

	template<typename L>
	void addListener(L l)
	{
		auto callable = new Closure<L, void (Types...)>(l);
		_callables.push_back(callable);
	}

	void call(Types... args)
	{
		//vector<Callable<void (Types...)>*> callablesToRemove;

		for (auto el : _callables) {
		//	try {
				(*el)(args...);
		//	}
		//	catch (...) {
		//		callablesToRemove.push_back(el);
		//	}
		}

		//if (callablesToRemove.size() > 0) {
		//	for (el : callablesToRemove) {
		//		remove(callables_.begin(), callables_.end(), el);
		//		delete el;
		//	}
		//}
	}

private:
	vector<Callable<void (Types...)>*> _callables;
};